﻿using System;
using System.Collections.Generic;
using System.Text;
using WiimoteLib;
using System.Windows.Forms;

namespace HelperLib
{
   public class WiimoteEventWrapper
   {
      private bool StateA, StateB, State1, State2;
      public event EventHandler<ButtonStateChangedEventArgs> OnButtonAChanged;
      public event EventHandler<ButtonStateChangedEventArgs> OnButtonBChanged;
      public event EventHandler<ButtonStateChangedEventArgs> OnButton1Changed;
      public event EventHandler<ButtonStateChangedEventArgs> OnButton2Changed;

      private bool StateRight, StateLeft, StateUp, StateDown;
      public event EventHandler<ButtonStateChangedEventArgs> OnButtonLeftChanged;
      public event EventHandler<ButtonStateChangedEventArgs> OnButtonRightChanged;
      public event EventHandler<ButtonStateChangedEventArgs> OnButtonUpChanged;
      public event EventHandler<ButtonStateChangedEventArgs> OnButtonDownChanged;


      public event EventHandler<ButtonStateChangedEventArgs> OnButtonMinusChanged; bool StateMinus;
      public event EventHandler<ButtonStateChangedEventArgs> OnButtonPlusChanged; bool StatePlus;
      public event EventHandler<ButtonStateChangedEventArgs> OnButtonHomeChanged; bool StateHome;

      public event EventHandler<ButtonStateChangedEventArgs> OnButtonCChanged; bool StateC;
      public event EventHandler<ButtonStateChangedEventArgs> OnButtonZChanged; bool StateZ;

      private Timer MeanTimer;

      public event EventHandler<Point3FUpdateEventArgs> OnWiiAccelUpdate;
      public event EventHandler<Point3FUpdateEventArgs> OnNunchukAccelUpdate;
      public event EventHandler<Point2FUpdateEventArgs> OnNunchukJoystickUpdate;

      private readonly CalcMean meanWiiX = new CalcMean();
      private readonly CalcMean meanWiiY = new CalcMean();
      private readonly CalcMean meanWiiZ = new CalcMean();

      private readonly CalcMean meanNunX = new CalcMean();
      private readonly CalcMean meanNunY = new CalcMean();
      private readonly CalcMean meanNunZ = new CalcMean();

      private readonly CalcMean meanNunJoyX = new CalcMean();
      private readonly CalcMean meanNunJoyY = new CalcMean();

      private void InvokeOnButtonChanged(EventHandler<ButtonStateChangedEventArgs> handler, bool Pressed)
      {
         if (handler != null)
         {
            handler(this,new ButtonStateChangedEventArgs(Pressed));
         }
      }


      private readonly Wiimote wm ;
      public WiimoteEventWrapper(Wiimote wm)
      {
         this.wm = wm;
         wm.WiimoteChanged += ParseWiimoteChangedEvent;
         wm.WiimoteExtensionChanged += ParseWiimoteExtensionChangedEvent;
         wm.SetReportType(InputReport.IRExtensionAccel, true);

         MeanTimer = new Timer
                        {
                           Interval = 50,
                           Enabled = true
                        };
         MeanTimer.Tick += MeanTimer_Tick;
      }

      void MeanTimer_Tick(object sender, EventArgs e)
      {
         if(OnWiiAccelUpdate != null)
         {
            OnWiiAccelUpdate(this,new Point3FUpdateEventArgs(new Point3F{X=meanWiiX.Mean(),Y=meanWiiY.Mean(),Z=meanWiiZ.Mean()}));
         }
         if(OnNunchukAccelUpdate != null)
         {
            OnNunchukAccelUpdate(this,new Point3FUpdateEventArgs(new Point3F{X=meanNunX.Mean(),Y=meanNunY.Mean(),Z=meanNunZ.Mean()}));
         }
         if(OnNunchukJoystickUpdate!= null)
         {
            OnNunchukJoystickUpdate(this,new Point2FUpdateEventArgs(meanNunJoyX.Mean(),meanNunJoyY.Mean()));
         }
      }
      ~WiimoteEventWrapper()
      {
         wm.WiimoteChanged -= ParseWiimoteChangedEvent;
         wm.WiimoteExtensionChanged -= ParseWiimoteExtensionChangedEvent;
      }

      public int MeanInterval
      {
         get { return MeanTimer.Interval; }
         set { MeanTimer.Interval = value; }
      }

      public void ParseWiimoteExtensionChangedEvent(object sender, WiimoteExtensionChangedEventArgs eventArgs)
      {
         if (eventArgs.Inserted)
            wm.SetReportType(InputReport.IRExtensionAccel, true);
         else
            wm.SetReportType(InputReport.IRAccel, true);
      }

      public void ParseWiimoteChangedEvent(object sender, WiimoteChangedEventArgs eventArgs)
      {
         CheckButtonState(OnButtonAChanged, eventArgs.WiimoteState.ButtonState.A, ref StateA);
         CheckButtonState(OnButtonBChanged, eventArgs.WiimoteState.ButtonState.B, ref StateB);
         CheckButtonState(OnButton1Changed, eventArgs.WiimoteState.ButtonState.One, ref State1);
         CheckButtonState(OnButton2Changed, eventArgs.WiimoteState.ButtonState.Two, ref State2);

         CheckButtonState(OnButtonLeftChanged, eventArgs.WiimoteState.ButtonState.Left, ref StateLeft);
         CheckButtonState(OnButtonRightChanged, eventArgs.WiimoteState.ButtonState.Right, ref StateRight);
         CheckButtonState(OnButtonUpChanged, eventArgs.WiimoteState.ButtonState.Up, ref StateUp);
         CheckButtonState(OnButtonDownChanged, eventArgs.WiimoteState.ButtonState.Down, ref StateDown);

         CheckButtonState(OnButtonMinusChanged, eventArgs.WiimoteState.ButtonState.Minus, ref StateMinus);
         CheckButtonState(OnButtonPlusChanged, eventArgs.WiimoteState.ButtonState.Plus, ref StatePlus);
         CheckButtonState(OnButtonHomeChanged, eventArgs.WiimoteState.ButtonState.Home, ref StateHome);

         CheckButtonState(OnButtonZChanged, eventArgs.WiimoteState.NunchukState.Z, ref StateZ);
         CheckButtonState(OnButtonCChanged, eventArgs.WiimoteState.NunchukState.C, ref StateC);


         meanWiiX.Add(eventArgs.WiimoteState.AccelState.Values.X);
         meanWiiY.Add(eventArgs.WiimoteState.AccelState.Values.Y);
         meanWiiZ.Add(eventArgs.WiimoteState.AccelState.Values.Z);

         meanNunX.Add(eventArgs.WiimoteState.NunchukState.AccelState.Values.X);
         meanNunY.Add(eventArgs.WiimoteState.NunchukState.AccelState.Values.Y);
         meanNunZ.Add(eventArgs.WiimoteState.NunchukState.AccelState.Values.Z);
         
         meanNunJoyX.Add(eventArgs.WiimoteState.NunchukState.Joystick.X);
         meanNunJoyY.Add(eventArgs.WiimoteState.NunchukState.Joystick.Y);
      }

      void CheckButtonState(EventHandler<ButtonStateChangedEventArgs> ChangedEvent,bool State, ref bool SaveState)
      {
           if (State != SaveState)
         {
            SaveState = State;
            InvokeOnButtonChanged(ChangedEvent, SaveState);
         }
      }
   }
   public class ButtonStateChangedEventArgs : EventArgs
   {
      public ButtonStateChangedEventArgs(bool Pressed)
      {
         this.Pressed = Pressed;
      }
      public bool Pressed { get; set; }
   }
   public class Point3FUpdateEventArgs : EventArgs
   {
      public Point3FUpdateEventArgs(Point3F Coordinates)
      {
         this.Coordinates = Coordinates;
      }
      public Point3F Coordinates { get; set; }
   }
   public class Point2FUpdateEventArgs : EventArgs
   {
      public Point2FUpdateEventArgs(float X, float Y)
      {
         this.X = X;
         this.Y = Y;
      }
      public float X { get; set; }
      public float Y { get; set; }
   }
}
